from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.generics import ListAPIView
from apps.oaauth.models import OADepartment,UserStatusChoices
from apps.oaauth.serializers import DepartmentSerializer
from rest_framework.views import APIView
from .serializers import AddStaffSerializer,ActiveStaffSerializer,StaffUploadSerializer
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.conf import settings
from utils import aeser
from django.urls import reverse #视图反转，将视图名反转为链接
from .tasks import send_mail_task
from django.views import View
from django.http.response import JsonResponse
from urllib import parse
from rest_framework import generics
from rest_framework import exceptions
from apps.oaauth.serializers import UserSerializer
from .paginations import StaffListPagination
from rest_framework import viewsets
from rest_framework import mixins
from datetime import datetime
import json
import pandas as pd
from django.http.response import HttpResponse
from django.db import transaction


# 将发送邮件封装成一个函数
def send_active_email(request, email):
    # 发送邮件一个链接，让用户点击后跳转到激活的页面才能激活
    # 为了区分用户，在发送链接的邮件中，该链接中应包含用户的邮箱
    # 针对邮箱进行加密：AES加密
    aes = aeser.AESCipher(settings.SECRET_KEY)  # 密钥用setting中的，得到aes对象
    token = aes.encrypt(email)  # 邮箱进行加密

    active_path = reverse("staff:active_staff") + "?" + parse.urlencode({"token": token})  # 将token进行编码，防止传递中有特殊字符出错
    # reverse反向获取命名为active_staff的视图的url地址，staff指命名空间   /staff/active?token=xxxx

    # 组建成完整的url http://127.0.0.1:8000/staff/active?token=MOEJFvLaAqzqk4VAEQmrJiAkxA9XvHbOQ/QwoBgpEXPI7uG3YE6mBDtzdedITFYj
    active_url = request.build_absolute_uri(active_path)  # 将active_path添加到协议和域名后
    message = f"点击以下链接激活账号：{active_url}"
    subject = f'OA账户激活'
    # 同步方式发送邮件
    # send_mail(f'OA账户激活', recipient_list=[email], message=message, from_email=settings.DEFAULT_FROM_EMAIL)
    # 异步发送邮件
    send_mail_task.delay(email, subject, message)


OAUser = get_user_model()
class DepartmentListView(ListAPIView):
    queryset = OADepartment.objects.all()
    serializer_class = DepartmentSerializer


class ActiveStaffView(View):
    def get(self, request):
            # 获取token，并把token存储到cookie中，方便下次用户传过来
            # http://127.0.0.1:8000/staff/active?token=ZRUyfzug8KsQDe49MZnt8Lczkn2wuEG8nflmPjfBOMXu2vHOce8u1pwivKS7rwRj
            token = request.GET.get('token')
            response = render(request, 'active.html')
            response.set_cookie('token', token)
            return response

    def post(self, request):
        token = request.COOKIES.get('token') #从cookie中获取token
        try:
            # 解密token得到邮箱
            aes = aeser.AESCipher(settings.SECRET_KEY)
            email = aes.decrypt(token)
            serializer = ActiveStaffSerializer(data=request.POST) #对post请求中的数据进行序列化
            #类似继承自django中的view，要获取表单对象用request.POST
            #如果是继承restframework中的APIView,要获取表单对象用request.data
            if serializer.is_valid():
                #从验证过的数据中提取信息
                form_email = serializer.validated_data.get('email')
                user = serializer.validated_data.get('user')
                if email != form_email : #检查token解密的邮箱是否与表单邮箱一致
                    return JsonResponse({'code':400,'message':'邮箱错误！'})
                user.status = UserStatusChoices.ACTIVED #修改员工的激活状态
                user.save()
                return JsonResponse({'code':200})
            else:
                detail = list(serializer.errors.values())[0][0]
                return JsonResponse({"code":400,'message':detail})
        except Exception as e:
            return JsonResponse({'code':400,'message':'token错误！'})

class StaffViewSet(viewsets.GenericViewSet,  #继承混入类，创建，列表和更新模型的功能
                mixins.CreateModelMixin,
                mixins.ListModelMixin,
                mixins.UpdateModelMixin):
    queryset = OAUser.objects.all() # 设置视图的基本查询集为所有OAUser模型实例
    pagination_class = StaffListPagination # 指定用于分页的类为之前定义的StaffListPagination

    def get_serializer_class(self):
        if self.request.method in ['GET','PUT']: #get请求是用于获取员工列表，用员工的序列化
            return UserSerializer                #put请求用于更新员工的状态
        else:
            return AddStaffSerializer #否则就是添加员工，使用添加员工的序列化

    #重写update方法
    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True  #可接受部分参数的更新
        return super().update(request, *args, **kwargs)

    #获取员工列表
    # 获取员工列表
    def get_queryset(self):
        #<QueryDict: {'department_id': ['1'], 'realname': ['东东'], 'date_joined[]': ['2024-09-03', '2024-10-29'], 'page': ['1'], 'size': ['1']}>
        department_id = self.request.query_params.get('department_id')
        realname = self.request.query_params.get('realname')
        date_joined = self.request.query_params.getlist('date_joined[]') #get方法用于获取单个值，getlist方法用于获取列表值

        queryset = self.queryset
        # 返回员工列表逻辑：
        # 1. 如果是董事会的，那么返回所有员工
        # 2. 如果不是董事会的，但是是部门的leader，那么就返回部门的员工
        # 3. 如果不是董事会的，也不是部门leader，那么就抛出403 Forbidden错误
        user = self.request.user
        if user.department.name != '董事会':
            if user.uid != user.department.leader.uid:
                raise exceptions.PermissionDenied()
            else:
                queryset = queryset.filter(department_id=user.department_id)
        else:
            # 用户在董事会中，提供了部门id进行过滤
            if department_id:
                queryset = queryset.filter(department_id=department_id)

        if realname: #按姓名过滤
            queryset = queryset.filter(realname__icontains=realname)
        if date_joined: #按时间过滤
            # ['2024-10-01', '2024-10-10']
            try:
                start_date = datetime.strptime(date_joined[0], "%Y-%m-%d")
                #datetime.strptime：将元素格式专为datetime对象  "%Y-%m-%d"：年份四位数，月份日期两位数
                end_date = datetime.strptime(date_joined[1], "%Y-%m-%d")
                queryset = queryset.filter(date_joined__range=(start_date, end_date)) #date_joined__range表示范围查找
            except Exception:
                pass
        return queryset.order_by("-date_joined").all()


    #处理新增员工的请求
    def create(self, request, *args, **kwargs):
        #如果使用视图集，视图集会自动把request放到context中
        #如果直接继承APIView,需要手动将request对象传给序列化器的context参数
        serializer = AddStaffSerializer(data=request.data,context={'request':request})
        if serializer.is_valid():
            realname = serializer.validated_data['realname']
            email = serializer.validated_data['email']
            password = serializer.validated_data['password']
            print("add:",email)
            print(password)

            #1.保存用户数据
            #使用在用户模型中定义的方法创建实例
            user = OAUser.objects.create_user(email=email, realname=realname,password=password)
            department = request.user.department
            user.save()

            #2.发送激活邮件  I/O:网络请求，文件读写 使用异步操作
            send_active_email(request,email)

            return Response()
        else:
            return Response(data={'detail': list(serializer.errors.values())[0][0]}, status=status.HTTP_400_BAD_REQUEST)

from oaback1.celery import debug_task
class TestCeleryView(APIView):
    def get(self, request):
        #用celery异步执行debug_task这个任务
        debug_task.delay()
        return Response({"detail":'成功！'})

#下载员工表格的视图函数
class StaffDownLoadView(APIView):
    def get(self, request):
        # /staff/download?pks=[x,y]
        #['x','y']=>json格式字符串

        pks = request.query_params.get('pks') #获取员工的主键
        try:
            #print("pks1:",pks)
            pks = json.loads(pks) #用于将JSON格式的字符串解析成Python的数据结构
        except Exception:
            return Response(data={'员工参数错误！'},status=status.HTTP_400_BAD_REQUEST)
        try:
            current_user = request.user
            queryset = OAUser.objects
            if current_user.department.name != '董事会':
                if current_user.department.leader_id != current_user.uid:  # 不是董事会和部门老大没用权限
                    return Response({'detail': '无权限下载！'}, status.HTTP_403_FORBIDDEN)
                else:
                    # 部门老大可过滤到本部门的员工
                    queryset = queryset.filter(department_id=current_user.department_id)

            # 当前用户在董事会的情况
            queryset.filter(pk__in=pks)                    #外键
            result = queryset.values("realname", 'email', 'department__name', 'date_joined', 'status') #提取出需要的字段

            #使用pandas库将查询结果转换为DataFrame
            staff_df = pd.DataFrame(list(result)) #result此时为queryset对象，需要转换为列表
            staff_df = staff_df.rename( #重命名列名
                columns={'realname': '姓名', 'email': '邮箱', "department__name": '部门', 'date_jointed': '入职日期',
                         'status': '状态'})
            response = HttpResponse(content_type='application/xlsx') #创建一个HttpResponse对象，设置内容类型为application/xlsx
            response['Content-Disposition'] = 'attachment;filename =员工信息.xlsx' #设置响应头，使得浏览器能够提示保存文件
            #使用pd.ExcelWriter将DataFrame写入Excel文件，并通过HTTP响应返回
            with pd.ExcelWriter(response) as writer:
                staff_df.to_excel(writer, sheet_name='员工信息')
            return response
        except Exception as e:
            print(e)
            return Response({'detail':str(e)},status=status.HTTP_400_BAD_REQUEST)

class StaffUploadView(APIView):
    def post(self, request):
        serializer = StaffUploadSerializer(data=request.data)
        if serializer.is_valid():
            file = serializer.validated_data.get('file')
            current_user = request.user
            if current_user.department.name != '董事会' or current_user.department.leader_id != current_user.uid:
                return Response({"detail": "您没有权限访问！"}, status=status.HTTP_403_FORBIDDEN)

            staff_df = pd.read_excel(file)
            users = []
            for index, row in staff_df.iterrows():
                # 获取部门
                if current_user.department.name != '董事会':
                    department = current_user.department
                else:
                    try:
                        department = OADepartment.objects.filter(name=row['部门']).first()
                        if not department:
                            return Response({"detail": f"{row['部门']}不存在！"}, status=status.HTTP_400_BAD_REQUEST)
                    except Exception as e:
                        return Response({"detail": "部门列不存在！"}, status=status.HTTP_400_BAD_REQUEST)

                try:
                    email = row['邮箱']
                    realname = row['姓名']
                    password = "111111"
                    user = OAUser(email=email, realname=realname, department=department, status=UserStatusChoices.UNACTIVE)
                    user.set_password(password)
                    users.append(user)
                except Exception:
                    return Response({"detail": "请检查文件中邮箱、姓名、部门名称！"}, status=status.HTTP_400_BAD_REQUEST)
            try:
                # 原子操作（事务）
                with transaction.atomic():
                    # 统一把数据添加到数据库中
                    OAUser.objects.bulk_create(users)
            except Exception:
                return Response({"detail": "员工数据添加错误！"}, status=status.HTTP_400_BAD_REQUEST)

            # 异步给每个新增的员工发送邮件
            for user in users:
                send_active_email(request, user.email)
            return Response()
        else:
            detail = list(serializer.errors.values())[0][0]
            return Response({"detail": detail}, status=status.HTTP_400_BAD_REQUEST)

